前幾篇的文章對參數有一些介紹,這篇文章會對參數的各種狀態進行更詳細的介紹。
在介紹參數之前,一個函式在運行之前,會帶入那些參數。
var globalVariables = '全域變數';
var obj = {
afunction: function (para) {
var localVariables = '區域變數';
console.log(para, localVariables, arguments, this, globalVariables);
}
};
// 執行
obj.afunction('一段描述', 2, 3);
我們可以看到,這段程式碼在執行的時候帶入的參數是3個,但接受的 function 只有 para 一個參數,也就是說,para 這個參數只會對應到 一段描述 這個字串,其他的2、3沒有傳進去。
看一下執行的結果~
我們可以看到 globalVariables 以及 localVariables都有對應到正確的值,而全域變數之前的章節也有討論過,如果找不到就會向外尋找直到找到為止,不然就回傳 not defined。
this的部分後面會再詳細的討論,這裡就先跳過。
重點是又多了一個 arguments 的變數,而且他好像是一個陣列,裝著'一段描述', 2, 3 的三個值。
但其實這個 arguments 被稱作 類陣列 ,但其實他不是陣列。雖然它可以被 for 迴圈處理內部的資料,但對於大部分陣列操作的指令他都無法執行。
function callName (a) {
console.log(a); // 小明
}
callName('小明');
上述執行的結果應該很明顯就是小明沒有甚麼好講的對吧~
那麼如果改成下面這樣呢?
function callName (a) {
console.log(a); // 小明
var a;
console.log(a); // 小明
}
callName('小明');
其實執行起來也還是小明喔!
原因是因為,我們再宣告一個變數的時候,這個變數名稱已經存在的時候,這個宣告就是無效的。
所以 var a;
是無效的,自然 a 就還是保持在小明的狀態。
那接下來我們把 a 改成 杰倫 呢?
function callName (a) {
console.log(a); // 小明
var a;
console.log(a); // 小明
a = '杰倫';
console.log(a); // 杰倫
}
callName('小明');
這時候就會是杰倫了,所以要改變內部的參數,直接覆蓋就可以了!
那麼重頭戲來了喔~!
如果我今天在裡面定義的是 函式陳述式呢?
根據之前學過的觀念是,函式陳述式會最早被寫入在記憶體空間中。
我們來實際操作看看
function callName (a) {
console.log(a);
function a () {}
var a;
console.log(a);
a = '杰倫';
console.log(a);
}
callName('小明');
很明顯在 a 還沒被杰倫覆蓋之前,傳入的小明就被 函式陳述式 給附蓋了。
所以雖然 函式陳述式 會最早被寫入在記憶體空間中,但最早是指在這個函式內的 {}
的最早。
因此 函式陳述式 並不會比 '小明' 這個參數還早,所以顯示的結果才是 函式陳述式。
我們再定義函式接收的參數名稱的時候,注意的只有參數的數量,參數的名稱都是可以自定義的,只要不要重複就好。
我們接下來來看看下面的例子:
function callMore (d,c,b,a){
console.log(d,c,b,a);
}
var a = 'a';
var b = 'b';
var c = 'c';
callMore(a, b ,c);
目前雖然傳了3個參數進去,但函式接受的參數定義是4個,因此最後一個 a 就會在函式內被定義為 undefined。
看一下範例吧~!
function callObject (obj) {
obj.name = '杰倫家';
}
var family = {
name: '小明家'
}
callObject(family);
console.log(family);
所以這邊執行後的結果很明顯就是 family.name 會被改成 杰倫家。
這邊也要提醒一下,盡量避免傳入物件類型的資料後,又在函是內部修改資料內容,避免不預期的結果。
當然也是有人利用這種特性進行撰寫,但其實這樣的撰寫風格不易追蹤,維護成本也較高。
因此不太建議這麼寫。
function FnB (fn) {
fn('小明');
}
FnB(function (a) {
console.log(a);
});
這樣的函式直接執行,我們就先把參數預定在 FnB
中,等到執行的時候,傳入ㄧ個 function,而 function 就會接收到 FnB
中的參數,並做ㄧ些處理。
我們也可以改寫成
function callSomeone (name) {
console.log(name + '你好');
}
function FnB (fn) {
fn('小明');
}
FnB(callSomeone);
這樣的寫法,我們把 callSomeone 賦予到 FnB 的參數 fn上。
我們是透過函式表達式的方式傳入到 FnB 的 function 中,因此真正執行的地方是在 callSomeone 的 function 裡面。
而這樣呼叫的方法呢,我們又稱作 callback function。
剛剛有說到 arguments 是一個類陣列,每個函是在運行的時候都會有,他不需要特別宣告就可以取用。
他會接受所有傳進來的值,並以一個類似陣列的結構乘裝著,但他不是真正的陣列。
function callArg (a) {
console.log(a, arguments);
}
callArg(1,2,3,'a','5');
我們可以對這個 arguments 做 for 迴圈的取值動作
function callArg (a) {
console.log(a, arguments);
for (var i = 0; i < arguments.length; i ++) {
console.log(arguments[i]);
}
}
callArg(1,2,3,'a','5');
但我們就沒辦法對她使用 forEach 的方法
function callArg (a) {
console.log(a, arguments);
arguments.forEach(function () {});
}
callArg(1,2,3,'a','5');
關於甚麼是類陣列,在這個章節還不需要先學習。
只要知道 arguments 是在函是運行的時候自帶的變數,並且會乘裝ㄧ切傳入的值,這樣就可以嚕~
沒有問題的話我們就可以往下一篇文章邁進了! 希望對各位有幫助~汪汪!